﻿using HML.Design;
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Reflection;
using System.Windows.Forms;

namespace HML
{
    /// <summary>
    /// 步骤流程控件
    /// </summary>
    [Description("步骤流程控件")]
    [DefaultProperty("Items")]
    [DefaultEvent("ActiveIndexChanged")]
    [TypeConverter(typeof(StepProgressConverter))]
    [Designer(typeof(StepProgressDesigner))]
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(StepProgress), "Controls.StepProgress.Resources.StepProgress.bmp")]
    public class StepProgress : DpiControl, ISkinObject
    {
        #region 主题

        private SkinObjectXmlMetadata skinObjectXmlMetadata = null;
        /// <summary>
        /// 主题对象在主题文件信息
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual SkinObjectXmlMetadata SkinObjectXmlMetadata
        {
            get
            {
                if (this.skinObjectXmlMetadata == null)
                    this.skinObjectXmlMetadata = new SkinObjectXmlMetadata(Assembly.GetAssembly(typeof(StepProgress)).GetName().Name, typeof(StepProgress).Name);

                return this.skinObjectXmlMetadata;
            }
        }

        private SkinController skinController = null;
        /// <summary>
        /// 主题控制器
        /// </summary>
        [Description("主题控制器")]
        [Category("杂项")]
        [PropertyOrder(-360)]
        [DefaultValue(null)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinController SkinController
        {
            get { return this.skinController; }
            set
            {
                if (this.skinController == value)
                    return;

                if (this.skinController != null)
                    this.skinController.RemoveSkinObject(this);

                this.skinController = value;

                if (this.skinController != null)
                    this.skinController.AddSkinObject(this);
            }
        }

        private SkinEnabledState skinEnabled= SkinEnabledState.Auto;
        /// <summary>
        /// 主题是否启用
        /// </summary>
        [Description("主题是否启用")]
        [Category("杂项")]
        [PropertyOrder(-300)]
        [DefaultValue(SkinEnabledState.Auto)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinEnabledState SkinEnabled
        {
            get { return this.skinEnabled; }
            set
            {
                if (this.skinEnabled == value)
                    return;

                this.skinEnabled = value;
                this.OnSkinChanged();
            }
        }

        private SkinStyle skinStyle = SkinStyle.Normal;
        /// <summary>
        /// 主题风格
        /// </summary>
        [Description("主题风格")]
        [Category("杂项")]
        [PropertyOrder(-260)]
        [DefaultValue(SkinStyle.Normal)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinStyle SkinStyle
        {
            get { return this.skinStyle; }
            set
            {
                if (this.skinStyle == value)
                    return;

                this.skinStyle = value;
                this.OnSkinChanged();
            }
        }

        private StyleAppearanceObject stateAppearance;
        /// <summary>
        /// 风格外观
        /// </summary>
        [Description("风格外观")]
        [Category("杂项")]
        [PropertyOrder(-200)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public StyleAppearanceObject StyleAppearance
        {
            get
            {
                if (this.stateAppearance == null)
                    this.stateAppearance = new StyleAppearanceObject(this, null);
                return this.stateAppearance;
            }
        }

        /// <summary>
        /// 主题已更改
        /// </summary>
        public virtual void OnSkinChanged()
        {
            SkinManager.SyncSkinValueToProperty(this);
            this.Invalidate();
        }

        private ISkinObject followSkinObject = null;
        /// <summary>
        /// 主题设置跟随指定主题对象（自己的设置不再生效，提供给代码使用）
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Localizable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual ISkinObject FollowSkinObject
        {
            get { return this.followSkinObject; }
            set
            {
                if (this.followSkinObject == value)
                    return;

                this.followSkinObject = value;
                this.OnSkinChanged();
            }
        }

        public virtual bool GetSkinObjectSkinStateCore()
        {
            return SkinManager.GetSkinObjectSkinState(this.FollowSkinObject ?? this);
        }

        void ISkinObject.InitializeInvalidate()
        {
            throw new NotImplementedException();
        }

        void ISkinObject.Invalidate()
        {
            this.Invalidate();
        }

        #endregion

        #region 新增事件

        private static readonly object EventActiveIndexChanged = new object();
        /// <summary>
        /// 已激活到的流程索引更改事件
        /// </summary>
        [Description("已激活到的流程索引更改事件")]
        public event EventHandler ActiveIndexChanged
        {
            add { Events.AddHandler(EventActiveIndexChanged, value); }
            remove { Events.RemoveHandler(EventActiveIndexChanged, value); }
        }

        #endregion

        #region 停用事件

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyEventHandler KeyDown
        {
            add { base.KeyDown += value; }
            remove { base.KeyDown -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyEventHandler KeyUp
        {
            add { base.KeyUp += value; }
            remove { base.KeyUp -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyPressEventHandler KeyPress
        {
            add { base.KeyPress += value; }
            remove { base.KeyPress -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event PreviewKeyDownEventHandler PreviewKeyDown
        {
            add { base.PreviewKeyDown += value; }
            remove { base.PreviewKeyDown -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TabIndexChanged
        {
            add { base.TabIndexChanged += value; }
            remove { base.TabIndexChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TabStopChanged
        {
            add { base.TabStopChanged += value; }
            remove { base.TabStopChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TextChanged
        {
            add { base.TextChanged += value; }
            remove { base.TextChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler RightToLeftChanged
        {
            add { base.RightToLeftChanged += value; }
            remove { base.RightToLeftChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ImeModeChanged
        {
            add { base.ImeModeChanged += value; }
            remove { base.ImeModeChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageChanged
        {
            add { base.BackgroundImageChanged += value; }
            remove { base.BackgroundImageChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageLayoutChanged
        {
            add { base.BackgroundImageLayoutChanged += value; }
            remove { base.BackgroundImageLayoutChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackColorChanged
        {
            add { base.BackColorChanged += value; }
            remove { base.BackColorChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ForeColorChanged
        {
            add { base.ForeColorChanged += value; }
            remove { base.ForeColorChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler Click
        {
            add { base.Click += value; }
            remove { base.Click -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler DoubleClick
        {
            add { base.DoubleClick += value; }
            remove { base.DoubleClick -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseClick
        {
            add { base.MouseClick += value; }
            remove { base.MouseClick -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseDoubleClick
        {
            add { base.MouseDoubleClick += value; }
            remove { base.MouseDoubleClick -= value; }
        }
        #endregion

        #region 新增属性

        private StepProgressOrientation orientation = StepProgressOrientation.HorizontalBottom;
        /// <summary>
        /// 流程节点方向位置
        /// </summary>
        [Description("流程节点方向位置")]
        [Category("杂项")]
        [PropertyOrder(-198)]
        [DefaultValue(StepProgressOrientation.HorizontalBottom)]
        public StepProgressOrientation Orientation
        {
            get { return this.orientation; }
            set
            {
                if (this.orientation == value)
                    return;

                this.orientation = value;
                this.InitializeElement();
                this.Invalidate();
            }
        }

        private LRPadding lRPadding = new LRPadding(8, 8);
        /// <summary>
        /// 左右内边距
        /// </summary>
        [Description("左右内边距")]
        [Category("杂项")]
        [PropertyOrder(-197)]
        [DefaultValue(typeof(LRPadding), "8, 8")]
        public LRPadding LRPadding
        {
            get { return this.lRPadding; }
            set
            {
                if (value.Left <= 0)
                    value.Left = 0;
                if (value.Right <= 0)
                    value.Right = 0;

                if (this.lRPadding == value)
                    return;

                this.lRPadding = value;
                this.InitializeElement();
                this.Invalidate();
            }
        }

        private TBPadding tBPadding = new TBPadding(8, 8);
        /// <summary>
        /// 上下内边距
        /// </summary>
        [Description("上下内边距")]
        [Category("杂项")]
        [PropertyOrder(-196)]
        [DefaultValue(typeof(TBPadding), "8, 8")]
        public TBPadding TBPadding
        {
            get { return this.tBPadding; }
            set
            {
                if (value.Top <= 0)
                    value.Top = 0;
                if (value.Bottom <= 0)
                    value.Bottom = 0;

                if (this.tBPadding == value)
                    return;

                this.tBPadding = value;
                this.InitializeElement();
                this.Invalidate();
            }
        }

        private int itemBorderThickness = 2;
        /// <summary>
        /// 流程节点边框厚度
        /// </summary>
        [Description("流程节点边框厚度")]
        [Category("杂项")]
        [PropertyOrder(-195)]
        [DefaultValue(2)]
        public int ItemBorderThickness
        {
            get { return this.itemBorderThickness; }
            set
            {
                if (this.itemBorderThickness == value || value < 0)
                    return;

                this.itemBorderThickness = value;
                this.Invalidate();
            }
        }

        private int itemSize = 22;
        /// <summary>
        /// 流程节点Size
        /// </summary>
        [Description("流程节点Size")]
        [PropertyOrder(-194)]
        [DefaultValue(22)]
        public int ItemSize
        {
            get { return this.itemSize; }
            set
            {
                if (this.itemSize == value || value <= 0)
                    return;

                this.itemSize = value;
                this.InitializeElement();
                this.Invalidate();
            }
        }

        private int itemDistance = 60;
        /// <summary>
        /// 流程节点间间距
        /// </summary>
        [Description("流程节点间间距")]
        [Category("杂项")]
        [PropertyOrder(-192)]
        [DefaultValue(60)]
        public int ItemDistance
        {
            get { return this.itemDistance; }
            set
            {
                if (this.itemDistance == value || value < 0)
                    return;

                this.itemDistance = value;
                this.InitializeElement();
                this.Invalidate();
            }
        }

        private bool itemCompletionMarkVisible = true;
        /// <summary>
        /// 是否显示流程节点完成标记
        /// </summary>
        [Description("是否显示流程节点完成标记")]
        [Category("杂项")]
        [PropertyOrder(-190)]
        [DefaultValue(true)]
        public bool ItemCompletionMarkVisible
        {
            get { return this.itemCompletionMarkVisible; }
            set
            {
                if (this.itemCompletionMarkVisible == value)
                    return;

                this.itemCompletionMarkVisible = value;
                this.Invalidate();
            }
        }

        private int itemTextDistance = 5;
        /// <summary>
        /// 流程节点与文本间距
        /// </summary>
        [Description("流程节点与文本间距")]
        [Category("杂项")]
        [PropertyOrder(-188)]
        [DefaultValue(5)]
        public int ItemTextDistance
        {
            get { return this.itemTextDistance; }
            set
            {
                if (this.itemTextDistance == value)
                    return;

                this.itemTextDistance = value;
                this.Invalidate();
            }
        }

        private StepProgressItemCollection procedureItemCollection;
        /// <summary>
        /// 流程节点集合
        /// </summary>
        [Description("流程节点集合")]
        [Category("杂项")]
        [PropertyOrder(-186)]
        [DefaultValue(null)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public StepProgressItemCollection Items
        {
            get
            {
                if (this.procedureItemCollection == null)
                    this.procedureItemCollection = new StepProgressItemCollection(this);
                return this.procedureItemCollection;
            }
        }

        private TipObject tip;
        /// <summary>
        /// 提示信息
        /// </summary>
        [Description("提示信息")]
        [Category("杂项")]
        [PropertyOrder(-152)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public TipObject Tip
        {
            get
            {
                if (this.tip == null)
                    this.tip = new TipObject(this);
                return this.tip;
            }
        }

        private int completionIndex = -1;
        /// <summary>
        /// 已完成到的流程节点索引
        /// </summary>
        [Browsable(false)]
        [DefaultValue(-1)]
        public int CompletionIndex
        {
            get { return this.completionIndex; }
            set
            {
                if (this.completionIndex == value || value < -1 || value >= Items.Count)
                    return;

                this.completionIndex = value;
                this.Invalidate();

                this.OnActiveIndexChanged(EventArgs.Empty);
            }
        }

        #endregion

        #region 重写属性

        protected override Size DefaultSize
        {
            get { return new Size(220, 60); }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected override ImeMode DefaultImeMode
        {
            get { return ImeMode.Disable; }
        }

        #endregion

        #region 停用属性

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Padding Padding
        {
            get { return base.Padding; }
            set { base.Padding = value; }
        }
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new int TabIndex
        {
            get { return base.TabIndex; }
            set { base.TabIndex = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new bool TabStop
        {
            get { return base.TabStop; }
            set { base.TabStop = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override string Text
        {
            get { return base.Text; }
            set { base.Text = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override RightToLeft RightToLeft
        {
            get { return base.RightToLeft; }
            set { base.RightToLeft = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ImeMode ImeMode
        {
            get { return base.ImeMode; }
            set { base.ImeMode = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Image BackgroundImage
        {
            get { return base.BackgroundImage; }
            set { base.BackgroundImage = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override ImageLayout BackgroundImageLayout
        {
            get { return base.BackgroundImageLayout; }
            set { base.BackgroundImageLayout = value; }
        }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Color BackColor
        {
            get { return this.StyleAppearance.BackColor; }
            set { }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Color ForeColor
        {
            get { return this.StyleAppearance.Item.Normal.TextColor; }
            set { }
        }

        #endregion

        #region 字段

        /// <summary>
        ///  提示信息
        /// </summary>
        private ToolTipPlus tooltip;
        /// <summary>
        /// 当前提示信息索引
        /// </summary>
        private int currentTipIndex = -2;

        /// <summary>
        /// 文本格式
        /// </summary>
        protected static StringFormat text_sf = new StringFormat() { FormatFlags = StringFormatFlags.NoWrap, Alignment = StringAlignment.Center, Trimming = StringTrimming.None };

        #endregion

        public StepProgress()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.StandardClick, false);
            SetStyle(ControlStyles.StandardDoubleClick, false);

            this.TabStop = false;
            this.OnSkinChanged();
        }

        #region 重写

        protected override void OnScaleDpiChangedInitialize()
        {
            this.InitializeElement();
            this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;

            NativeMethods.TEXTMETRIC font_metrics = ControlHelper.GetFontMetrics(this.Handle, this.Font);
            Padding scale_padding = new Padding((int)(this.Padding.Left * this.ScaleDpi), (int)(this.Padding.Top * this.ScaleDpi), (int)(this.Padding.Right * this.ScaleDpi), (int)(this.Padding.Bottom * this.ScaleDpi));
            int scale_borderThickness = (int)Math.Ceiling(this.ItemBorderThickness * this.ScaleDpi);
            int scale_text_flowTextDistance = (int)Math.Ceiling(this.ItemTextDistance * this.ScaleDpi);
            RectangleF scale_rectf = new Rectangle(this.ClientRectangle.Left + scale_padding.Left, this.ClientRectangle.Top + scale_padding.Top, this.ClientRectangle.Width - scale_padding.Left - scale_padding.Right, this.ClientRectangle.Height - scale_padding.Top - scale_padding.Bottom);

            Pen flow_line_pen = new Pen(Color.White, scale_borderThickness);
            SolidBrush flow_sb = new SolidBrush(Color.White);

            for (int i = 0; i < this.Items.Count; i++)
            {
                StepProgressItem current_item = this.Items[i];

                // 流程节点背景
                flow_sb.Color = (i <= this.CompletionIndex - 1) ? this.StyleAppearance.Item.Completion.BackColor : this.StyleAppearance.Item.Normal.BackColor;
                g.FillEllipse(flow_sb, current_item.RectF);

                // 流程节点边框
                flow_line_pen.Color = (i <= this.CompletionIndex - 1) ? this.StyleAppearance.Item.Completion.BorderColor : this.StyleAppearance.Item.Normal.BorderColor;
                g.DrawEllipse(flow_line_pen, ControlHelper.TransformRectangleF(current_item.RectF, scale_borderThickness));

                // 流程节点间隔线
                if (i > 0 && i < this.Items.Count)
                {
                    StepProgressItem prev_item = this.Items[i - 1];
                    PointF flow_line_strat_point = new PointF(prev_item.RectF.Right - scale_borderThickness + scale_borderThickness / 2f, prev_item.RectF.Y + current_item.RectF.Height / 2f);
                    PointF flow_line_end_point = new PointF(current_item.RectF.X + scale_borderThickness - scale_borderThickness / 2f, current_item.RectF.Y + current_item.RectF.Height / 2);
                    if (this.Orientation == StepProgressOrientation.VerticalLeft || this.Orientation == StepProgressOrientation.VerticalRight)
                    {
                        flow_line_strat_point = new PointF(prev_item.RectF.X + current_item.RectF.Width / 2f, prev_item.RectF.Bottom - scale_borderThickness + scale_borderThickness / 2);
                        flow_line_end_point = new PointF(current_item.RectF.X + current_item.RectF.Width / 2f, current_item.RectF.Y + scale_borderThickness - scale_borderThickness / 2);
                    }
                    g.DrawLine(flow_line_pen, flow_line_strat_point, flow_line_end_point);
                }

                // 流程节点文本
                Size text_size = new Size((int)Math.Ceiling(g.MeasureString(current_item.Text, this.Font, int.MaxValue, StringFormat.GenericTypographic).Width), font_metrics.GetFontRealHeight());
                PointF text_point = PointF.Empty;
                if (this.Orientation == StepProgressOrientation.HorizontalBottom)
                {
                    text_point = new PointF(current_item.RectF.X + (current_item.RectF.Width - text_size.Width) / 2f, current_item.RectF.Y - scale_text_flowTextDistance - text_size.Height);
                }
                if (this.Orientation == StepProgressOrientation.HorizontalTop)
                {
                    text_point = new PointF(current_item.RectF.X + (current_item.RectF.Width - text_size.Width) / 2f, current_item.RectF.Bottom + scale_text_flowTextDistance);
                }
                else if (this.Orientation == StepProgressOrientation.VerticalLeft)
                {
                    text_point = new PointF(current_item.RectF.Right + scale_text_flowTextDistance, current_item.RectF.Y + (current_item.RectF.Height - text_size.Height) / 2f);
                }
                else if (this.Orientation == StepProgressOrientation.VerticalRight)
                {
                    text_point = new PointF(current_item.RectF.X - scale_text_flowTextDistance - text_size.Width, current_item.RectF.Y + (current_item.RectF.Height - text_size.Height) / 2f);
                }

                flow_sb.Color = (i <= this.CompletionIndex - 1) ? this.StyleAppearance.Item.Completion.TextColor : this.StyleAppearance.Item.Normal.TextColor;
                g.DrawString(current_item.Text, this.Font, flow_sb, text_point, StringFormat.GenericTypographic);
            }

            flow_line_pen.Dispose();
            flow_sb.Dispose();

            //流程节点索引
            if (this.ItemCompletionMarkVisible)
            {
                float scale_flow_Size = (float)Math.Ceiling(this.ItemSize * this.ScaleDpi) - scale_borderThickness * 3;
                float padding = ((float)Math.Ceiling(this.ItemSize * this.ScaleDpi) - scale_flow_Size) / 2f;
                Pen check_fore_pen = new Pen(Color.White, scale_flow_Size / 7f);
                g.SmoothingMode = SmoothingMode.AntiAlias;
                for (int i = 0; i < this.Items.Count; i++)
                {
                    check_fore_pen.Color = (i <= this.CompletionIndex - 1) ? this.StyleAppearance.Item.Completion.CompletionSymbolColor : this.StyleAppearance.Item.Normal.CompletionSymbolColor;
                    if (i <= this.CompletionIndex - 1)
                    {
                        RectangleF rect = new RectangleF(this.Items[i].RectF.X + padding, this.Items[i].RectF.Y + padding, scale_flow_Size, scale_flow_Size);
                        float min_grid = scale_flow_Size / 10f;
                        PointF[] check_char_line = new PointF[] {
                        new PointF(rect.X+min_grid,rect.Y+ min_grid * 4.5f),
                        new PointF(rect.X+min_grid *4,rect.Y+  min_grid * 7),
                        new PointF(rect.X+min_grid*8f ,rect.Y+  min_grid*2)
                        };

                        g.DrawLines(check_fore_pen, check_char_line);
                    }
                }
                g.SmoothingMode = SmoothingMode.Default;
                check_fore_pen.Dispose();
            }

        }

        protected override void OnLeave(EventArgs e)
        {
            base.OnLeave(e);

            if (this.currentTipIndex > -2)
            {
                this.HideTip();
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            int index = this.GetSelectedIndex(this.PointToClient(Control.MousePosition));
            if (index > -1)
            {
                if (this.Tip.Visible && this.currentTipIndex != index)
                {
                    this.ShowTip(index);
                }
            }
            else
            {
                if (this.currentTipIndex > -2)
                {
                    this.HideTip();
                }
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);

            if (this.currentTipIndex > -2)
            {
                this.HideTip();
            }
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            this.InitializeElement();
            this.Invalidate();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.tooltip != null)
                {
                    this.tooltip.Dispose();
                    this.tooltip = null;
                }
                for (int i = 0; i < this.Items.Count; i++)
                {
                    if (this.Items[i].GP != null)
                    {
                        this.Items[i].GP.Dispose();
                        this.Items[i].GP = null;
                    }
                }
            }
            base.Dispose(disposing);
        }

        #endregion

        #region 虚方法

        protected virtual void OnActiveIndexChanged(EventArgs e)
        {
            EventHandler handler = Events[EventActiveIndexChanged] as EventHandler;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        #endregion

        #region 公开方法

        /// <summary>
        /// 初始化控件内部元素布局
        /// </summary>
        public void InitializeElement()
        {
            this.InitializeProcedureRectangle();
        }

        /// <summary>
        /// 初始化流程节点rect
        /// </summary>
        internal void InitializeProcedureRectangle()
        {
            for (int i = 0; i < this.Items.Count; i++)
            {
                this.InitializeProcedureRectangle(this.Items[i]);
            }
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 初始化流程节点rect
        /// </summary>
        /// <param name="item"></param>
        internal void InitializeProcedureRectangle(StepProgressItem item)
        {
            TBPadding scale_tBPadding = new TBPadding((int)Math.Ceiling(this.TBPadding.Top * this.ScaleDpi), (int)Math.Ceiling(this.TBPadding.Bottom * this.ScaleDpi));
            LRPadding scale_lRPadding = new LRPadding((int)Math.Ceiling(this.LRPadding.Left * this.ScaleDpi), (int)Math.Ceiling(this.LRPadding.Right * this.ScaleDpi));
            int scale_distance = (int)Math.Ceiling(this.ItemDistance * this.ScaleDpi);
            int scale_flow_radius = (int)Math.Ceiling(this.ItemSize * this.ScaleDpi / 2f);
            RectangleF scale_rectf = new Rectangle(this.ClientRectangle.Left + scale_lRPadding.Left, this.ClientRectangle.Top + scale_tBPadding.Top, this.ClientRectangle.Width - scale_lRPadding.Left - scale_lRPadding.Right, this.ClientRectangle.Height - scale_tBPadding.Top - scale_tBPadding.Bottom);

            int index = this.Items.IndexOf(item);
            if (this.Orientation == StepProgressOrientation.HorizontalBottom)
            {
                float x = scale_rectf.Left + index * (scale_flow_radius * 2f + scale_distance);
                float y = scale_rectf.Bottom - scale_flow_radius * 2;
                item.RectF = new RectangleF(x, y, scale_flow_radius * 2, scale_flow_radius * 2);
            }
            else if (this.Orientation == StepProgressOrientation.HorizontalTop)
            {
                float x = scale_rectf.Left + index * (scale_flow_radius * 2f + scale_distance);
                float y = scale_rectf.Top;
                item.RectF = new RectangleF(x, y, scale_flow_radius * 2, scale_flow_radius * 2);
            }
            else if (this.Orientation == StepProgressOrientation.VerticalLeft)
            {
                float x = scale_rectf.Left;
                float y = scale_rectf.Top + index * (scale_flow_radius * 2f + scale_distance);
                item.RectF = new RectangleF(x, y, scale_flow_radius * 2, scale_flow_radius * 2);
            }
            else if (this.Orientation == StepProgressOrientation.VerticalRight)
            {
                float x = scale_rectf.Right - scale_flow_radius * 2;
                float y = scale_rectf.Top + index * (scale_flow_radius * 2f + scale_distance);
                item.RectF = new RectangleF(x, y, scale_flow_radius * 2, scale_flow_radius * 2);
            }
            if (item.GP == null)
            {
                GraphicsPath gp = new GraphicsPath();
                gp.AddEllipse(item.RectF);
                item.GP = gp;
            }
            else
            {
                item.GP.Reset();
                item.GP.AddEllipse(item.RectF);
            }
        }

        /// <summary>
        /// 获取鼠标进入的流程节点索引
        /// </summary>
        /// <param name="point">当前鼠标坐标</param>
        /// <returns></returns>
        private int GetSelectedIndex(Point point)
        {
            for (int i = 0; i < this.Items.Count; i++)
            {
                if (this.Items[i].GP != null && this.Items[i].GP.IsVisible(point))
                {
                    return i;
                }
            }
            return -1;
        }

        /// <summary>
        /// 显示指定索引流程提示信息
        /// </summary>
        /// <param name="index">指定流程索引</param>
        private void ShowTip(int index)
        {
            if (this.tooltip == null)
            {
                this.tooltip = new ToolTipPlus();
                this.tooltip.TitleVisible = false;
                this.tooltip.BorderVisible = true;
                this.tooltip.UseAnimation = false;

                this.tooltip.StyleAppearance.BorderColor = this.StyleAppearance.Tip.BorderColor;
                this.tooltip.StyleAppearance.BackColor = this.StyleAppearance.Tip.BackColor;
                this.tooltip.StyleAppearance.TextColor = this.StyleAppearance.Tip.TextColor;
                this.tooltip.Font = this.Tip.Font;
            }
            this.tooltip.MinSize = this.Tip.MinSize;
            this.tooltip.MaxSize = this.Tip.MaxSize;

            ToolTipPlusAnchors anchor = ToolTipPlusAnchors.TopCenter;
            if (this.Orientation == StepProgressOrientation.HorizontalBottom)
            {
                anchor = ToolTipPlusAnchors.BottomCenter;
            }
            else if (this.Orientation == StepProgressOrientation.VerticalLeft)
            {
                anchor = ToolTipPlusAnchors.LeftCenter;
            }
            else if (this.Orientation == StepProgressOrientation.VerticalRight)
            {
                anchor = ToolTipPlusAnchors.RightCenter;
            }
            Rectangle rect = new Rectangle((int)this.Items[index].RectF.X, (int)this.Items[index].RectF.Y, (int)this.Items[index].RectF.Width, (int)this.Items[index].RectF.Height);
            this.tooltip.ToolTipTitle = this.Items[index].Text;
            string str = this.Items[index].TipText == String.Empty ? " " : this.Items[index].TipText;
            this.tooltip.Show(str, this, rect, anchor);
            this.currentTipIndex = index;
        }

        /// <summary>
        /// 隐藏提示
        /// </summary>
        private void HideTip()
        {
            this.tooltip.Hide(this);
            this.currentTipIndex = -2;
        }

        #endregion

        #region 类

        [TypeConverter(typeof(PropertyOrderConverter))]
        public class TipObject
        {
            private StepProgress owner = null;
            internal TipObject(StepProgress owner) { this.owner = owner; }

            #region 属性

            private bool visible = false;
            /// <summary>
            /// 是否显示提示信息
            /// </summary>
            [Description("是否显示提示信息")]
            [PropertyOrder(-190)]
            [DefaultValue(false)]
            public bool Visible
            {
                get { return this.visible; }
                set
                {
                    if (this.visible == value)
                        return;

                    this.visible = value;
                    if (!this.visible && this.owner.tooltip != null)
                    {
                        this.owner.tooltip.Hide(this.owner);
                        this.owner.tooltip.Dispose();
                        this.owner.tooltip = null;
                    }
                }
            }

            private Size maxSize = new Size(400, 0);
            /// <summary>
            /// 提示信息最大Size
            /// </summary>
            [Description("提示信息最大Size")]
            [PropertyOrder(-188)]
            [DefaultValue(typeof(Size), "400, 0")]
            [RefreshProperties(RefreshProperties.All)]
            public Size MaxSize
            {
                get { return this.maxSize; }
                set
                {
                    if (this.maxSize == value)
                        return;

                    this.maxSize = value;

                    if (this.minSize.Width != 0 && this.maxSize.Width != 0 && this.minSize.Width > this.maxSize.Width)
                    {
                        this.minSize.Width = this.maxSize.Width;
                    }
                    if (this.minSize.Height != 0 && this.maxSize.Height != 0 && this.minSize.Height > this.maxSize.Height)
                    {
                        this.minSize.Height = this.maxSize.Height;
                    }
                }
            }

            private Size minSize = new Size(30, 10);
            /// <summary>
            /// 提示信息最小Size
            /// </summary>
            [Description("提示信息最小Size")]
            [PropertyOrder(-186)]
            [DefaultValue(typeof(Size), "30, 10")]
            [RefreshProperties(RefreshProperties.All)]
            public Size MinSize
            {
                get { return this.minSize; }
                set
                {
                    if (this.minSize == value)
                        return;

                    this.minSize = value;

                    if (this.maxSize.Width != 0 && this.minSize.Width != 0 && this.maxSize.Width < this.minSize.Width)
                    {
                        this.maxSize.Width = this.minSize.Width;
                    }
                    if (this.maxSize.Height != 0 && this.minSize.Height != 0 && this.maxSize.Height < this.minSize.Height)
                    {
                        this.maxSize.Height = this.minSize.Height;
                    }
                }
            }

            private Font font = null;
            /// <summary>
            /// 提示信息文本字体
            /// </summary>
            [Description("提示信息文本字体")]
            [PropertyOrder(-178)]
            public Font Font
            {
                get
                {
                    if (this.font != null)
                    {
                        return this.font;
                    }
                    if (((StepProgress)this.owner).Parent != null)
                    {
                        return ((StepProgress)this.owner).Parent.Font;
                    }
                    return Control.DefaultFont;
                }
                set
                {
                    if (((StepProgress)this.owner).Parent != null)
                    {
                        if (((StepProgress)this.owner).Parent.Font.Equals(value))
                        {
                            this.font = null;
                            if (((StepProgress)this.owner).tooltip != null)
                                ((StepProgress)this.owner).tooltip.Font = this.Font;
                            return;
                        }
                    }
                    if (Control.DefaultFont.Equals(value))
                    {
                        this.font = null;
                        if (((StepProgress)this.owner).tooltip != null)
                            ((StepProgress)this.owner).tooltip.Font = this.Font;
                        return;
                    }

                    this.font = value;
                    if (((StepProgress)this.owner).tooltip != null)
                        ((StepProgress)this.owner).tooltip.Font = this.Font;
                }
            }
            private bool ShouldSerializeFont()
            {
                return (this.font != null && !this.font.Equals(Control.DefaultFont));
            }
            private void ResetFont()
            {
                this.font = null;
                if (this.owner.tooltip != null)
                    this.owner.tooltip.Font = this.Font;
            }

            #endregion

        }

        #endregion

        #region 外观

        public class StyleAppearanceObject : AppearanceObjectBase
        {
            internal StyleAppearanceObject(ISkinObject owner, AppearanceObjectBase parent) : base(owner, parent) { }

            #region 属性

            private Color skinBackColor = Color.Empty;
            private readonly Color defaultBackColor = SystemColors.Control;
            private Color backColor = Color.Empty;
            /// <summary>
            /// 背景颜色
            /// </summary>
            [Description("背景颜色")]
            [PropertyOrder(-195)]
            [SkinProperty(true, true)]
            public Color BackColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore() && this.skinBackColor != Color.Empty)
                    {
                        return this.skinBackColor;
                    }

                    if (this.backColor != Color.Empty)
                    {
                        return this.backColor;
                    }

                    if (((Control)this.owner).Parent != null)
                    {
                        return ((Control)this.owner).Parent.BackColor;
                    }

                    return this.defaultBackColor;
                }
                set
                {
                    if (this.backColor == value)
                        return;

                    this.backColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeBackColor()
            {
                return this.backColor != Color.Empty;
            }
            private void ResetBackColor()
            {
                this.backColor = Color.Empty;
                this.Invalidate();
            }

            private ItemObjectAppearanceObject item;
            /// <summary>
            /// 选项
            /// </summary>
            [Description("选项")]
            [PropertyOrder(-194)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
            [SkinProperty(true, false)]
            public ItemObjectAppearanceObject Item
            {
                get
                {
                    if (this.item == null)
                        this.item = new ItemObjectAppearanceObject(this.owner, this);
                    return this.item;
                }
            }

            private TipAppearanceObject tip;
            /// <summary>
            /// 提示
            /// </summary>
            [Description("提示")]
            [PropertyOrder(-193)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
            [SkinProperty(true, false)]
            public TipAppearanceObject Tip
            {
                get
                {
                    if (this.tip == null)
                        this.tip = new TipAppearanceObject(this.owner, this);
                    return this.tip;
                }
            }

            #endregion

            public class ItemObjectAppearanceObject : AppearanceObjectBase
            {
                internal ItemObjectAppearanceObject(ISkinObject owner, AppearanceObjectBase parent) : base(owner, parent) { }

                #region 属性

                private ItemAppearanceObject normal;
                /// <summary>
                /// 正常状态
                /// </summary>
                [Description("正常状态")]
                [PropertyOrder(-196)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
                [SkinProperty(true, false)]
                public ItemAppearanceObject Normal
                {
                    get
                    {
                        if (this.normal == null)
                            this.normal = new ItemAppearanceObject(this.owner, this, SystemColors.GradientActiveCaption, SystemColors.Window, SystemColors.ActiveCaption, SystemColors.Window);
                        return this.normal;
                    }
                }

                private ItemAppearanceObject completion;
                /// <summary>
                /// 已完成状态
                /// </summary>
                [Description("已完成状态")]
                [PropertyOrder(-194)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
                [SkinProperty(true, false)]
                public ItemAppearanceObject Completion
                {
                    get
                    {
                        if (this.completion == null)
                            this.completion = new ItemAppearanceObject(this.owner, this, SystemColors.ActiveCaption, SystemColors.GradientActiveCaption, SystemColors.ActiveCaption, SystemColors.Window);
                        return this.completion;
                    }
                }

                #endregion

                public class ItemAppearanceObject : AppearanceObjectBase
                {
                    internal ItemAppearanceObject(ISkinObject owner, AppearanceObjectBase parent, Color borderColor, Color backColor, Color textColor, Color completionMarkColor) : base(owner, parent)
                    {
                        this.defaultBorderColor = borderColor;
                        this.defaultBackColor = backColor;
                        this.defaultTextColor = textColor;
                        this.defaultCompletionSymbolColor = completionMarkColor;
                    }

                    #region 属性

                    private Color skinBorderColor = Color.Empty;
                    private readonly Color defaultBorderColor = Color.Empty;
                    private Color borderColor = Color.Empty;
                    /// <summary>
                    /// 边框颜色
                    /// </summary>
                    [Description("边框颜色")]
                    [PropertyOrder(-159)]
                    [SkinProperty(true, false)]
                    public Color BorderColor
                    {
                        get
                        {
                            if (this.owner.GetSkinObjectSkinStateCore())
                            {
                                return this.skinBorderColor;
                            }

                            if (this.borderColor != Color.Empty)
                            {
                                return this.borderColor;
                            }

                            return this.defaultBorderColor;
                        }
                        set
                        {
                            if (this.borderColor == value)
                                return;

                            this.borderColor = value;
                            this.Invalidate();
                        }
                    }
                    private bool ShouldSerializeBorderColor()
                    {
                        return this.borderColor != Color.Empty;
                    }
                    private void ResetBorderColor()
                    {
                        this.borderColor = Color.Empty;
                        this.Invalidate();
                    }

                    private Color skinBackColor = Color.Empty;
                    private readonly Color defaultBackColor = Color.Empty;
                    private Color backColor = Color.Empty;
                    /// <summary>
                    /// 背景颜色
                    /// </summary>
                    [Description("背景颜色")]
                    [PropertyOrder(-158)]
                    [SkinProperty(true, false)]
                    public Color BackColor
                    {
                        get
                        {
                            if (this.owner.GetSkinObjectSkinStateCore())
                            {
                                return this.skinBackColor;
                            }

                            if (this.backColor != Color.Empty)
                            {
                                return this.backColor;
                            }

                            return this.defaultBackColor;
                        }
                        set
                        {
                            if (this.backColor == value)
                                return;

                            this.backColor = value;
                            this.Invalidate();
                        }
                    }
                    private bool ShouldSerializeBackColor()
                    {
                        return this.backColor != Color.Empty;
                    }
                    private void ResetBackColor()
                    {
                        this.backColor = Color.Empty;
                        this.Invalidate();
                    }

                    private Color skinTextColor = Color.Empty;
                    private readonly Color defaultTextColor = Color.Empty;
                    private Color textColor = Color.Empty;
                    /// <summary>
                    /// 文本颜色
                    /// </summary>
                    [Description("文本颜色")]
                    [PropertyOrder(-157)]
                    [SkinProperty(true, false)]
                    public Color TextColor
                    {
                        get
                        {
                            if (this.owner.GetSkinObjectSkinStateCore())
                            {
                                return this.skinTextColor;
                            }

                            if (this.textColor != Color.Empty)
                            {
                                return this.textColor;
                            }

                            return this.defaultTextColor;
                        }
                        set
                        {
                            if (this.textColor == value)
                                return;

                            this.textColor = value;
                            this.Invalidate();
                        }
                    }
                    private bool ShouldSerializeTextColor()
                    {
                        return this.textColor != Color.Empty;
                    }
                    private void ResetTextColor()
                    {
                        this.textColor = Color.Empty;
                        this.Invalidate();
                    }

                    private Color skinCompletionSymbolColor = Color.Empty;
                    private Color defaultCompletionSymbolColor = Color.Empty;
                    private Color completionSymbolColor = Color.Empty;
                    /// <summary>
                    /// 完成标记颜色
                    /// </summary>
                    [Description("完成标记颜色")]
                    [PropertyOrder(-142)]
                    [SkinProperty(true, false)]
                    public Color CompletionSymbolColor
                    {
                        get
                        {
                            if (this.owner.GetSkinObjectSkinStateCore())
                            {
                                return this.skinCompletionSymbolColor;
                            }

                            if (this.completionSymbolColor != Color.Empty)
                            {
                                return this.completionSymbolColor;
                            }

                            return this.defaultCompletionSymbolColor;
                        }
                        set
                        {
                            if (this.completionSymbolColor == value)
                                return;

                            this.completionSymbolColor = value;
                            this.Invalidate();
                        }
                    }
                    private bool ShouldSerializeCompletionSymbolColor()
                    {
                        return this.completionSymbolColor != Color.Empty;
                    }
                    private void ResetCompletionSymbolColor()
                    {
                        this.completionSymbolColor = Color.Empty;
                        this.Invalidate();
                    }

                    #endregion

                }

            }

            public class TipAppearanceObject : AppearanceObjectBase
            {
                internal TipAppearanceObject(ISkinObject owner, AppearanceObjectBase parent) : base(owner, parent) { }

                #region 属性

                private Color skinBorderColor = Color.Empty;
                private readonly Color defaultBorderColor = SystemColors.ActiveCaption;
                private Color borderColor = Color.Empty;
                /// <summary>
                /// 提示信息边框颜色
                /// </summary>
                [Description("提示信息边框颜色")]
                [PropertyOrder(-199)]
                [SkinProperty(true, false)]
                public Color BorderColor
                {
                    get
                    {
                        if (this.owner.GetSkinObjectSkinStateCore())
                        {
                            return this.skinBorderColor;
                        }

                        if (this.borderColor != Color.Empty)
                        {
                            return this.borderColor;
                        }

                        return this.defaultBorderColor;
                    }
                    set
                    {
                        if (this.borderColor == value)
                            return;

                        this.borderColor = value;
                        this.Invalidate();
                    }
                }
                private bool ShouldSerializeBorderColor()
                {
                    return this.borderColor != Color.Empty;
                }
                private void ResetBorderColor()
                {
                    this.borderColor = Color.Empty;
                    this.Invalidate();
                }

                private Color skinBackColor = Color.Empty;
                private readonly Color defaultBackColor = SystemColors.GradientActiveCaption;
                private Color backColor = Color.Empty;
                /// <summary>
                /// 提示信息背景颜色
                /// </summary>
                [Description("提示信息背景颜色")]
                [PropertyOrder(-194)]
                [SkinProperty(true, false)]
                public Color BackColor
                {
                    get
                    {
                        if (this.owner.GetSkinObjectSkinStateCore())
                        {
                            return this.skinBackColor;
                        }

                        if (this.backColor != Color.Empty)
                        {
                            return this.backColor;
                        }

                        return this.defaultBackColor;
                    }
                    set
                    {
                        if (this.backColor == value)
                            return;

                        this.backColor = value;
                        this.Invalidate();
                    }
                }
                private bool ShouldSerializeBackColor()
                {
                    return this.backColor != Color.Empty;
                }
                private void ResetBackColor()
                {
                    this.backColor = Color.Empty;
                    this.Invalidate();
                }

                private Color skinTextColor = Color.Empty;
                private readonly Color defaultTextColor = SystemColors.Window;
                private Color textColor = Color.Empty;
                /// <summary>
                /// 提示信息文本颜色
                /// </summary>
                [Description("提示信息文本颜色")]
                [PropertyOrder(-157)]
                [SkinProperty(true, false)]
                public Color TextColor
                {
                    get
                    {
                        if (this.owner.GetSkinObjectSkinStateCore())
                        {
                            return this.skinTextColor;
                        }

                        if (this.textColor != Color.Empty)
                        {
                            return this.textColor;
                        }

                        return this.defaultTextColor;
                    }
                    set
                    {
                        if (this.textColor == value)
                            return;

                        this.textColor = value;
                        this.Invalidate();
                    }
                }
                private bool ShouldSerializeTextColor()
                {
                    return this.textColor != Color.Empty;
                }
                private void ResetTextColor()
                {
                    this.textColor = Color.Empty;
                    this.Invalidate();
                }

                #endregion

            }

        }

        #endregion

    }
}
